package com.vhans.bus.user.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.lang.Assert;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.vhans.bus.comm.model.dto.DisableDTO;
import com.vhans.bus.comm.model.dto.EmailDTO;
import com.vhans.bus.comm.model.dto.PasswdDTO;
import com.vhans.bus.user.domain.User;
import com.vhans.bus.user.domain.vo.UserInfoVO;
import com.vhans.bus.user.mapper.UserMapper;
import com.vhans.bus.user.service.IUserService;
import com.vhans.core.enums.FilePathEnum;
import com.vhans.core.redis.RedisService;
import com.vhans.core.strategy.context.FileStrategyContext;
import com.vhans.core.utils.SecurityUtils;
import com.vhans.core.utils.data.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.List;

import static com.vhans.core.constant.CommonConstant.TRUE;
import static com.vhans.core.constant.RedisConstant.CODE_KEY_USER;

/**
 * 用户业务接口实现类
 *
 * @author vhans.db
 * @date 2022/12/05 15:32
 **/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private RedisService redisService;

    @Autowired
    private FileStrategyContext fileStrategyContext;

    @Override
    public List<User> listUser(User.Query query) {
        return userMapper.listUser(query);
    }

    @Override
    public UserInfoVO getLoginInfo() {
        int userId = StpUtil.getLoginIdAsInt();
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .select(User::getAvatar, User::getNickname, User::getEmail, User::getSex, User::getUsername,
                        User::getIntro, User::getLoginType, User::getIpSource, User::getLoginTime)
                .eq(User::getId, userId));
        return UserInfoVO.builder()
                .id(userId)
                .avatar(user.getAvatar())
                .nickname(user.getNickname())
                .username(user.getUsername())
                .email(user.getEmail())
                .intro(user.getIntro())
                .sex(user.getSex())
                .loginType(user.getLoginType())
                .ipSource(user.getIpSource())
                .loginTime(user.getLoginTime())
                .build();
    }

    @Override
    public User getUserById(Integer id) {
        int userId = StpUtil.getLoginIdAsInt();
        User user = userMapper.selectById(id);
        Assert.notNull(user, StringUtils.format("不存在用户【{}】,ID={}", user.getNickname(), id));
        if (id != userId) {
            user.setPassword("");
            user.setLoginType(0);
            user.setIpSource(null);
            user.setIpAddress("");
        }
        return user;
    }

    @Override
    public List<User> searchUserList(String name) {
        return userMapper.searchUserList(name, StpUtil.getLoginIdAsInt());
    }

    @Override
    public void updateUser(User user) {
        int userId = StpUtil.getLoginIdAsInt();
        user.setId(userId);
        User oldUser = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .select(User::getUsername, User::getNickname)
                .eq(User::getId, userId));
        if (!oldUser.getUsername().equals(user.getUsername())) {
            User flagUser = userMapper.selectOne(new LambdaQueryWrapper<User>()
                    .select(User::getId)
                    .eq(User::getUsername, user.getUsername())
                    .ne(User::getNickname, oldUser.getNickname()));
            Assert.isNull(flagUser, "账号[" + user.getUsername() + "]已被使用");
        }
        if (StringUtils.isNotEmpty(user.getNickname())) {
            User flagUser = userMapper.selectOne(new LambdaQueryWrapper<User>()
                    .select(User::getId)
                    .eq(User::getNickname, user.getNickname())
                    .ne(User::getUsername, oldUser.getUsername()));
            Assert.isNull(flagUser, "昵称[" + user.getNickname() + "]已被使用");
        }
        userMapper.updateById(user);
    }

    @Override
    public void updateUserStatus(DisableDTO disable) {
        // 更新用户状态
        userMapper.updateById(User.builder()
                .id(disable.getId())
                .isDisable(disable.getIsDisable())
                .build());
        if (disable.getIsDisable().equals(TRUE)) {
            // 先踢下线
            StpUtil.logout(disable.getId());
            // 再封禁账号
            StpUtil.disable(disable.getId(), 86400);
        } else {
            // 解除封禁
            StpUtil.untieDisable(disable.getId());
        }
    }

    @Override
    public void kickOutUser(String token) {
        StpUtil.logoutByTokenValue(token);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateUserEmail(EmailDTO email) {
        verifyCode(email.getEmail(), email.getCode());
        userMapper.updateById(User.builder()
                .id(StpUtil.getLoginIdAsInt())
                .email(email.getEmail())
                .build());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public String updateUserAvatar(MultipartFile file) {
        // 头像上传
        String avatar = fileStrategyContext.executeUploadStrategy(file, FilePathEnum.AVATAR.getPath());
        // 更新用户头像
        userMapper.updateById(User.builder()
                .id(StpUtil.getLoginIdAsInt())
                .avatar(avatar)
                .build());
        return avatar;
    }

    @Override
    public void updatePassword(PasswdDTO passwd) {
        Integer userId = StpUtil.getLoginIdAsInt();
        // 查询旧密码是否正确
        User user = userMapper.selectOne(new LambdaQueryWrapper<User>()
                .eq(User::getId, userId));
        Assert.notNull(user, "用户不存在");
        Assert.isTrue(SecurityUtils.checkPw(user.getPassword(), passwd.getOldPassword()), "旧密码校验不通过!");
        // 正确则修改密码
        String newPassword = SecurityUtils.sha256Encrypt(passwd.getNewPassword());
        user.setPassword(newPassword);
        userMapper.updateById(user);
    }

    @Override
    public void resetPassword(Integer userId) {
        // 用户是否存在
        User user = userMapper.selectById(userId);
        Assert.isFalse(StringUtils.isNull(user), "用户不存在！");
        // 根据用户ID重置密码
        userMapper.update(user, new LambdaUpdateWrapper<User>()
                .set(User::getPassword, SecurityUtils.sha256Encrypt("123456"))
                .eq(User::getId, userId));
    }

    /**
     * 校验验证码
     *
     * @param username 用户名
     * @param code     验证码
     */
    private void verifyCode(String username, String code) {
        String sysCode = redisService.getObject(CODE_KEY_USER + username);
        Assert.notBlank(sysCode, "验证码未发送或已过期！");
        Assert.isTrue(sysCode.equals(code), "验证码错误，请重新输入！");
    }
}